﻿using Crap4Net;
using System;
using Crap4Net.CoverageParsers;
using NUnit.Framework;
using System.Collections.Generic;

namespace Crap4Net.UnitTests.CoverageParsersTests
{
    [TestFixture]
    public class PartCoverParserTests
    {
        private const string PARTCOVER_FILEPATH = @"UnitTestData\PartCoverFiles\";
        private const string ASSEMBLY_NAME = "DummyProject";
        private const string NAME_SPACE = "dummyProject";

        [Test]
        [ExpectedException(typeof(ApplicationException))]
        public void Data_FileNotLoaded_ThrowsException()
        {
            var target = new PartCoverageParser();
            var dummy = target.Data;
        }

        [Test]
        [ExpectedException(typeof(ArgumentException))]
        public void LoadData_InvalidFileName_throwsException()
        {
            var target = new PartCoverageParser();
            target.LoadData("NoSuchFile.xml");
        }

        [Test]
        public void LoadData_EmptyClass_ParseOnlyCtor()
        {
            var target = new PartCoverageParser();
            target.LoadData(PARTCOVER_FILEPATH+"EmptyClass.xml");
            var actual = target.Data;

            Assert.AreEqual(1, actual.Count);
            var method = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "class2", ".ctor", new string[] { });
            Assert.AreEqual(new CoverageDataEntry(method, 0), actual[0]);
        }

        [Test]
        public void LoadData_CtorMethod_ParseCtor()
        {
            var target = new PartCoverageParser();
            target.LoadData(PARTCOVER_FILEPATH+"ctor.xml");
            var actual = target.Data;

            Assert.AreEqual(1, actual.Count);
            var method = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", ".ctor", new string[] { });
            Assert.AreEqual(new CoverageDataEntry(method, 100), actual[0]);
        }

        [Test]
        public void LoadData_GenericMethod_ParsedCorrectly()
        {
            var target = new PartCoverageParser();
            target.LoadData(PARTCOVER_FILEPATH + "GenericMethod.xml");
            var actual = target.Data;

            Assert.AreEqual(1, actual.Count);
            var method = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", "GenericMethod<T>", new string[] { });
            Assert.AreEqual(new CoverageDataEntry(method, 100), actual[0]);
        }

        [Test]
        public void LoadData_FullCoverage_CoverageIs100()
        {
            var target = new PartCoverageParser();
            target.LoadData(PARTCOVER_FILEPATH + "MethodWithFullCoverage.xml");
            var actual = target.Data;

            Assert.AreEqual(1, actual.Count);
            var method = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", ".ctor", new string[] { });
            Assert.AreEqual(new CoverageDataEntry(method, 100), actual[0]);
        }

        [Test]
        public void LoadData_MethodWithMoreThenOneVisit_calculateCoverageProperly()
        {
            var target = new PartCoverageParser();
            target.LoadData(PARTCOVER_FILEPATH + "MethodWithMoreThenOneVisit.xml");
            var actual = target.Data;

            var method = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", "method1", new string[] { });
            var covData = new CoverageDataEntry(method, 90);
            var expected = new List<CoverageDataEntry>() { covData };

            CollectionAssert.AreEquivalent(expected, actual);
        }
        
        [Test]
        public void LoadData_NoCoverage_ReturnsZeroCoverage()
        {
            var target = new PartCoverageParser();
            target.LoadData(PARTCOVER_FILEPATH + "MethodWithNoCoverage.xml");
            var actual = target.Data;

            var method = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "class2", ".ctor", new string[] { });
            var covData = new CoverageDataEntry(method, 0);
            var expected = new List<CoverageDataEntry>() { covData };

            CollectionAssert.AreEquivalent(expected, actual);

        }

        [Test]
        public void LoadData_PartialCoverage_CalculateCorrectCoverage()
        {
            var target = new PartCoverageParser();
            target.LoadData(@PARTCOVER_FILEPATH + "MethodWithPartialCoverage.xml");
            var actual = target.Data;

            var method = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", "method1", new string[] { });
            var covData = new CoverageDataEntry(method, 63);
            var expected = new List<CoverageDataEntry>() { covData };

            CollectionAssert.AreEquivalent(expected, actual);
        }

        [Test]
        public void LoadData_Property_returnResultforGetAndSet()
        {
            var target = new PartCoverageParser();
            target.LoadData(PARTCOVER_FILEPATH + "Property.xml");
            var actual = target.Data;

            var method = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", "get_SomeProperty", new string[] { });
            var getData = new CoverageDataEntry(method, 0);
            method = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", "set_SomeProperty", new string[] { "object" });
            var setData = new CoverageDataEntry(method, 0);
            var expected = new List<CoverageDataEntry>() { getData, setData };

            CollectionAssert.AreEquivalent(expected, actual);
        }

        [Test]
        public void LoadData_StaticCtor_ParsedCorrectly()
        {
            var target = new PartCoverageParser();
            target.LoadData(PARTCOVER_FILEPATH + "StaticCtor.xml");
            var actual = target.Data;

            var method = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", ".cctor", new string[] { });
            var covData = new CoverageDataEntry(method, 100);
            var expected = new List<CoverageDataEntry>() { covData};

            CollectionAssert.AreEquivalent(expected, actual);

        }

        [Test]
        public void LoadData_OverloadedMethod_ParseAllInstances()
        {
            var target = new PartCoverageParser();
            target.LoadData(PARTCOVER_FILEPATH + "OverLoadedMethod.xml");

            var actual = target.Data;

            var method1 = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", "method2", new string[] {"int" });
            var method2 = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", "method2", new string[] {"double" });
            var method3 = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", "method2", new string[] {"float" });
            var method4 = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", "method2", new string[] { });
            var expected = new List<CoverageDataEntry>() {
                new CoverageDataEntry(method1, 0), 
                new CoverageDataEntry(method2, 0), 
                new CoverageDataEntry(method3, 0), 
                new CoverageDataEntry(method4, 0) 
            };

            CollectionAssert.AreEquivalent(expected, actual);

        }

        [Test]
        public void Data_ValidFile_RetrievesCorrectData()
        {
            var target = new PartCoverageParser();
            target.LoadData(PARTCOVER_FILEPATH + "PartCoverResult.xml");
            var actual = target.Data;

            var method1 = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", "method1", new string[] {  });
            var method2 = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", "method2", new string[] { });
            var method3 = new MethodSignature(ASSEMBLY_NAME, NAME_SPACE, "Class1", ".ctor", new string[] { });
            var method4 = new MethodSignature("dummyTests", "dummyTests", "Class1Test", "method1Test", new string[] { });
            var method5 = new MethodSignature("dummyTests", "dummyTests", "Class1Test", ".ctor", new string[] { });
            var expected = new List<CoverageDataEntry>() {
                new CoverageDataEntry(method1, 63), 
                new CoverageDataEntry(method2, 0), 
                new CoverageDataEntry(method3, 100), 
                new CoverageDataEntry(method4, 100), 
                new CoverageDataEntry(method5, 100) 
            };

            CollectionAssert.AreEquivalent(expected, actual);

        }
    }
}
